package com.lumi.max.jnicall.serialoperate;

import android.content.Context;
import android.util.Log;

import com.ftdi.j2xx.D2xxManager;
import com.ftdi.j2xx.FT_Device;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;

/**
 * Created by LME09 on 2016/3/18.
 */
public class TN147Class extends SerialReadWrite {
    D2xxManager ftdid2xx;
    FT_Device ftDev = null;
    int DevCount = -1;
    int currentIndex = -1;
    int openIndex = 0;

    public int iavailable = 0;

    public boolean bReadThreadGoing = false;
    boolean uart_configured = false;

    public static final int READ_LENGTH = 1024;

    @Override
    public boolean getUartConfiged() {
        return uart_configured;
    }

    public void iniDevice(Context context){
        try {
            ftdid2xx = D2xxManager.getInstance(context);
        } catch (D2xxManager.D2xxException ex) {
            ex.printStackTrace();
        }
        int tempDevCount = ftdid2xx.createDeviceInfoList(context);

        if (tempDevCount > 0)
        {
            if( DevCount != tempDevCount )
            {
                DevCount = tempDevCount;
            }
        }
        else
        {
            DevCount = -1;
            currentIndex = -1;
        }
    }

    @Override
    public int getDevCount() {
        return DevCount;
    }



    @Override
    public boolean isDeviceOpen() {
        if (DevCount > 0 && ftDev != null){
            return true;
        }
        return false;
    }

    @Override
    public void setConfig(int baudRate, byte dataBit, byte stopBit, byte parity, byte flowControl) {
        if (ftDev==null ||!ftDev.isOpen()) {
            Log.e("j2xx", "SetConfig: device not open");
            return;
        }

        // configure our port
        // reset to UART mode for 232 devices
        ftDev.setBitMode((byte) 0, D2xxManager.FT_BITMODE_RESET);

        ftDev.setBaudRate(baudRate);

        switch (dataBit) {
            case 7:
                dataBit = D2xxManager.FT_DATA_BITS_7;
                break;
            case 8:
                dataBit = D2xxManager.FT_DATA_BITS_8;
                break;
            default:
                dataBit = D2xxManager.FT_DATA_BITS_8;
                break;
        }

        switch (stopBit) {
            case 1:
                stopBit = D2xxManager.FT_STOP_BITS_1;
                break;
            case 2:
                stopBit = D2xxManager.FT_STOP_BITS_2;
                break;
            default:
                stopBit = D2xxManager.FT_STOP_BITS_1;
                break;
        }

        switch (parity) {
            case 0:
                parity = D2xxManager.FT_PARITY_NONE;
                break;
            case 1:
                parity = D2xxManager.FT_PARITY_ODD;
                break;
            case 2:
                parity = D2xxManager.FT_PARITY_EVEN;
                break;
            case 3:
                parity = D2xxManager.FT_PARITY_MARK;
                break;
            case 4:
                parity = D2xxManager.FT_PARITY_SPACE;
                break;
            default:
                parity = D2xxManager.FT_PARITY_NONE;
                break;
        }

        ftDev.setDataCharacteristics(dataBit, stopBit, parity);

        short flowCtrlSetting;
        switch (flowControl) {
            case 0:
                flowCtrlSetting = D2xxManager.FT_FLOW_NONE;
                break;
            case 1:
                flowCtrlSetting = D2xxManager.FT_FLOW_RTS_CTS;
                break;
            case 2:
                flowCtrlSetting = D2xxManager.FT_FLOW_DTR_DSR;
                break;
            case 3:
                flowCtrlSetting = D2xxManager.FT_FLOW_XON_XOFF;
                break;
            default:
                flowCtrlSetting = D2xxManager.FT_FLOW_NONE;
                break;
        }

        // TODO : flow ctrl: XOFF/XOM
        // TODO : flow ctrl: XOFF/XOM
        ftDev.setFlowControl(flowCtrlSetting, (byte) 0x0b, (byte) 0x0d);

        uart_configured = true;
    }

    @Override
    public void writeData(byte[] OutData){
        if (ftDev == null || !ftDev.isOpen()) {
            Log.e("j2xx", "SendMessage: device not open");
            return;
        }

        ftDev.setLatencyTimer((byte) 16);
//		ftDev.purge((byte) (D2xxManager.FT_PURGE_TX | D2xxManager.FT_PURGE_RX));
        ftDev.write(OutData);
    }

//    @Override
//    public int readTask(char[] readData) {
//        if (ftDev == null){
//            return 0;
//        }
//        synchronized(ftDev)
//        {
//            byte [] readByteData;
//            iavailable = ftDev.getQueueStatus();
//            if (iavailable > 0) {
//                readByteData = new byte[READ_LENGTH];
//                if(iavailable > READ_LENGTH){
//                    iavailable = READ_LENGTH;
//                }
//
//                ftDev.read(readByteData, iavailable);
//                for (int i = 0; i < iavailable; i++) {
//                    readData[i] =  (char) readByteData[i];
//                }
//            }
//            return iavailable;
//        }
//    }


    @Override
    public String readTask() {
        if (ftDev == null){
            return null;
        }

        synchronized(ftDev)
        {
            byte [] readByteData;
            iavailable = ftDev.getQueueStatus();
            if (iavailable > 0) {
                readByteData = new byte[READ_LENGTH];
                if(iavailable > READ_LENGTH){
                    iavailable = READ_LENGTH;
                }

                ftDev.read(readByteData, iavailable);
                if(iavailable > 0) {
                    return toHex(readByteData, 0, iavailable);
//                    char[] data = new char[iavailable];
//                    byte[] dataRead = new byte[iavailable];
//                    for (int i = 0 ; i < iavailable; i++){
//                        dataRead[i] = readByteData[i];
//                    }
////                    data = getChars(dataRead);
////                    System.arraycopy(readByteData,0,data,0,data.length);
//                    return dataRead;
                }
            }
            return null;
        }
    }

    private char[] getChars (byte[] bytes) {
        Charset cs = Charset.forName ("UTF-8");
        ByteBuffer bb = ByteBuffer.allocate (bytes.length);
        bb.put (bytes);
        bb.flip ();
        CharBuffer cb = cs.decode (bb);

        return cb.array();
    }

    @Override
    public void enableRead(boolean flag){
        if (ftDev == null){
            return;
        }
        if(flag) {
            ftDev.purge((D2xxManager.FT_PURGE_TX));
            ftDev.restartInTask();
        }
        else{
            ftDev.stopInTask();
        }
    }

    @Override
    public void disconnectFunction()
    {
        DevCount = -1;
        currentIndex = -1;
        bReadThreadGoing = false;
        try {
            Thread.sleep(50);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }

        if(ftDev != null)
        {
            synchronized(ftDev)
            {
                if( ftDev.isOpen())
                {
                    ftDev.close();
                }
            }
        }
    }

    @Override
    public void connectFunction(Context context) {
        if (currentIndex != openIndex) {
            if (null == ftDev) {
                ftDev = ftdid2xx.openByIndex(context, openIndex);
            } else {
                synchronized (ftDev) {
                    ftDev = ftdid2xx.openByIndex(context, openIndex);
                }
            }
            uart_configured = false;
        } else {
            return;
        }

        if (ftDev.isOpen()){
            currentIndex = openIndex;
        }

        if (ftDev == null) {
            return;
        }

//        if (ftDev.isOpen())
//        {
//            currentIndex = openIndex;
//
//            if(!bReadThreadGoing)
//            {
//                read_thread = new readThread(handler);
//                read_thread.start();
//                bReadThreadGoing = true;
//            }
//        }
//        else
//        {
//        }
    }
}
